import { invoke } from '@tauri-apps/api/core';
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
import {
  AndroidKeyEventAction,
  AndroidMotionEventAction,
  AndroidMotionEventButtons,
  AndroidKeycode,
  AndroidMetastate,
  ScreenPowerMode,
  CopyKeyMode,
} from '@/types/android-events';

// Types for device control
export interface TouchEventParams {
  deviceId: string;
  action: AndroidMotionEventAction;
  pointerId: number;
  x: number;
  y: number;
  pressure: number;
}

export interface KeyEventParams {
  deviceId: string;
  action: AndroidKeyEventAction;
  keycode: AndroidKeycode;
  repeat: number;
  metastate: AndroidMetastate;
}

export interface TextInputParams {
  deviceId: string;
  text: string;
}

export interface ScrollEventParams {
  deviceId: string;
  x: number;
  y: number;
  hscroll: number;
  vscroll: number;
}

export interface ClipboardParams {
  deviceId: string;
  text: string;
  paste: boolean;
}

export interface DeviceReply {
  type: 'MetaData' | 'ClipboardChanged' | 'ClipboardSetAck' | 'UhidOutput';
  deviceName?: string;
  clipboard?: string;
  sequence?: number;
}

// Device control class
export class DeviceControl {
  private deviceId: string;
  private replyListener?: UnlistenFn;
  private onReplyCallback?: (reply: DeviceReply) => void;

  constructor(deviceId: string) {
    this.deviceId = deviceId;
  }

  // Start device control
  async start(port: number = 27183): Promise<void> {
    await invoke('start_device_control', {
      deviceId: this.deviceId,
      port,
    });

    // Setup reply listener
    this.replyListener = await listen<DeviceReply>('device-reply', (event) => {
      if (this.onReplyCallback) {
        this.onReplyCallback(event.payload);
      }
    });
  }

  // Stop device control
  async stop(): Promise<void> {
    if (this.replyListener) {
      this.replyListener();
      this.replyListener = undefined;
    }

    await invoke('stop_device_control', {
      deviceId: this.deviceId,
    });
  }

  // Set reply callback
  onReply(callback: (reply: DeviceReply) => void) {
    this.onReplyCallback = callback;
  }

  // Touch control methods
  async sendTouchDown(x: number, y: number, pointerId: number = 0): Promise<void> {
    await this.sendTouchEvent({
      deviceId: this.deviceId,
      action: AndroidMotionEventAction.ACTION_DOWN,
      pointerId,
      x,
      y,
      pressure: 1.0,
    });
  }

  async sendTouchMove(x: number, y: number, pointerId: number = 0): Promise<void> {
    await this.sendTouchEvent({
      deviceId: this.deviceId,
      action: AndroidMotionEventAction.ACTION_MOVE,
      pointerId,
      x,
      y,
      pressure: 1.0,
    });
  }

  async sendTouchUp(x: number, y: number, pointerId: number = 0): Promise<void> {
    await this.sendTouchEvent({
      deviceId: this.deviceId,
      action: AndroidMotionEventAction.ACTION_UP,
      pointerId,
      x,
      y,
      pressure: 0.0,
    });
  }

  async sendTouchEvent(params: TouchEventParams): Promise<void> {
    await invoke('send_touch_event', params);
  }

  // Key control methods
  async sendKeyPress(keycode: AndroidKeycode, metastate: AndroidMetastate = AndroidMetastate.META_NONE): Promise<void> {
    // Send key down
    await this.sendKeyEvent({
      deviceId: this.deviceId,
      action: AndroidKeyEventAction.ACTION_DOWN,
      keycode,
      repeat: 0,
      metastate,
    });

    // Send key up
    await this.sendKeyEvent({
      deviceId: this.deviceId,
      action: AndroidKeyEventAction.ACTION_UP,
      keycode,
      repeat: 0,
      metastate,
    });
  }

  async sendKeyEvent(params: KeyEventParams): Promise<void> {
    await invoke('send_key_event', params);
  }

  // Text input
  async sendText(text: string): Promise<void> {
    await invoke('send_text_input', {
      deviceId: this.deviceId,
      text,
    });
  }

  // Scroll control
  async sendScroll(x: number, y: number, hscroll: number, vscroll: number): Promise<void> {
    await invoke('send_scroll_event', {
      deviceId: this.deviceId,
      x,
      y,
      hscroll,
      vscroll,
    });
  }

  // System control methods
  async sendBackButton(): Promise<void> {
    await invoke('send_back_button', { deviceId: this.deviceId });
  }

  async sendHomeButton(): Promise<void> {
    await this.sendKeyPress(AndroidKeycode.KEYCODE_HOME);
  }

  async sendMenuButton(): Promise<void> {
    await this.sendKeyPress(AndroidKeycode.KEYCODE_MENU);
  }

  async rotateDevice(): Promise<void> {
    await invoke('rotate_device', { deviceId: this.deviceId });
  }

  // Clipboard operations
  async setClipboard(text: string, paste: boolean = false): Promise<void> {
    await invoke('set_clipboard', {
      deviceId: this.deviceId,
      text,
      paste,
    });
  }

  async getClipboard(): Promise<void> {
    await invoke('get_clipboard', { deviceId: this.deviceId });
  }

  // Panel control
  async expandNotificationPanel(): Promise<void> {
    await invoke('expand_notification_panel', { deviceId: this.deviceId });
  }

  async expandSettingsPanel(): Promise<void> {
    await invoke('expand_settings_panel', { deviceId: this.deviceId });
  }

  async collapsePanels(): Promise<void> {
    await invoke('collapse_panels', { deviceId: this.deviceId });
  }

  // Screen power control
  async setScreenPowerMode(mode: ScreenPowerMode): Promise<void> {
    await invoke('set_screen_power_mode', {
      deviceId: this.deviceId,
      mode,
    });
  }

  async turnScreenOff(): Promise<void> {
    await this.setScreenPowerMode(ScreenPowerMode.OFF);
  }

  async turnScreenOn(): Promise<void> {
    await this.setScreenPowerMode(ScreenPowerMode.NORMAL);
  }

  // Swipe gestures
  async swipe(startX: number, startY: number, endX: number, endY: number, duration: number = 300): Promise<void> {
    const steps = Math.ceil(duration / 16); // 60 FPS
    const deltaX = (endX - startX) / steps;
    const deltaY = (endY - startY) / steps;

    // Touch down
    await this.sendTouchDown(startX, startY);

    // Move in steps
    for (let i = 1; i < steps; i++) {
      const x = Math.round(startX + deltaX * i);
      const y = Math.round(startY + deltaY * i);
      await this.sendTouchMove(x, y);
      await new Promise(resolve => setTimeout(resolve, 16));
    }

    // Touch up
    await this.sendTouchUp(endX, endY);
  }

  // Common swipe gestures
  async swipeUp(distance: number = 500, duration: number = 300): Promise<void> {
    const centerX = 540; // Assuming 1080px width
    const centerY = 960; // Assuming 1920px height
    await this.swipe(centerX, centerY + distance / 2, centerX, centerY - distance / 2, duration);
  }

  async swipeDown(distance: number = 500, duration: number = 300): Promise<void> {
    const centerX = 540;
    const centerY = 960;
    await this.swipe(centerX, centerY - distance / 2, centerX, centerY + distance / 2, duration);
  }

  async swipeLeft(distance: number = 500, duration: number = 300): Promise<void> {
    const centerX = 540;
    const centerY = 960;
    await this.swipe(centerX + distance / 2, centerY, centerX - distance / 2, centerY, duration);
  }

  async swipeRight(distance: number = 500, duration: number = 300): Promise<void> {
    const centerX = 540;
    const centerY = 960;
    await this.swipe(centerX - distance / 2, centerY, centerX + distance / 2, centerY, duration);
  }

  // Tap gesture
  async tap(x: number, y: number): Promise<void> {
    await this.sendTouchDown(x, y);
    await new Promise(resolve => setTimeout(resolve, 50));
    await this.sendTouchUp(x, y);
  }

  // Long press gesture
  async longPress(x: number, y: number, duration: number = 500): Promise<void> {
    await this.sendTouchDown(x, y);
    await new Promise(resolve => setTimeout(resolve, duration));
    await this.sendTouchUp(x, y);
  }

  // Pinch gesture (zoom)
  async pinch(centerX: number, centerY: number, startDistance: number, endDistance: number, duration: number = 300): Promise<void> {
    const steps = Math.ceil(duration / 16);
    const deltaDistance = (endDistance - startDistance) / steps;

    // Start with two fingers
    await this.sendTouchEvent({
      deviceId: this.deviceId,
      action: AndroidMotionEventAction.ACTION_DOWN,
      pointerId: 0,
      x: centerX - startDistance / 2,
      y: centerY,
      pressure: 1.0,
    });

    await this.sendTouchEvent({
      deviceId: this.deviceId,
      action: AndroidMotionEventAction.ACTION_POINTER_DOWN,
      pointerId: 1,
      x: centerX + startDistance / 2,
      y: centerY,
      pressure: 1.0,
    });

    // Move fingers
    for (let i = 1; i < steps; i++) {
      const distance = startDistance + deltaDistance * i;
      
      await this.sendTouchEvent({
        deviceId: this.deviceId,
        action: AndroidMotionEventAction.ACTION_MOVE,
        pointerId: 0,
        x: Math.round(centerX - distance / 2),
        y: centerY,
        pressure: 1.0,
      });

      await this.sendTouchEvent({
        deviceId: this.deviceId,
        action: AndroidMotionEventAction.ACTION_MOVE,
        pointerId: 1,
        x: Math.round(centerX + distance / 2),
        y: centerY,
        pressure: 1.0,
      });

      await new Promise(resolve => setTimeout(resolve, 16));
    }

    // Release fingers
    await this.sendTouchEvent({
      deviceId: this.deviceId,
      action: AndroidMotionEventAction.ACTION_POINTER_UP,
      pointerId: 1,
      x: centerX + endDistance / 2,
      y: centerY,
      pressure: 0.0,
    });

    await this.sendTouchEvent({
      deviceId: this.deviceId,
      action: AndroidMotionEventAction.ACTION_UP,
      pointerId: 0,
      x: centerX - endDistance / 2,
      y: centerY,
      pressure: 0.0,
    });
  }

  // Volume control
  async volumeUp(): Promise<void> {
    await this.sendKeyPress(AndroidKeycode.KEYCODE_VOLUME_UP);
  }

  async volumeDown(): Promise<void> {
    await this.sendKeyPress(AndroidKeycode.KEYCODE_VOLUME_DOWN);
  }

  async mute(): Promise<void> {
    await this.sendKeyPress(AndroidKeycode.KEYCODE_MUTE);
  }
}

// Export singleton manager for managing multiple device controls
export class DeviceControlManager {
  private controls: Map<string, DeviceControl> = new Map();

  async connectDevice(deviceId: string, port?: number): Promise<DeviceControl> {
    if (this.controls.has(deviceId)) {
      return this.controls.get(deviceId)!;
    }

    const control = new DeviceControl(deviceId);
    await control.start(port);
    this.controls.set(deviceId, control);
    return control;
  }

  async disconnectDevice(deviceId: string): Promise<void> {
    const control = this.controls.get(deviceId);
    if (control) {
      await control.stop();
      this.controls.delete(deviceId);
    }
  }

  getControl(deviceId: string): DeviceControl | undefined {
    return this.controls.get(deviceId);
  }

  async disconnectAll(): Promise<void> {
    const promises = Array.from(this.controls.values()).map(control => control.stop());
    await Promise.all(promises);
    this.controls.clear();
  }
}

export const deviceControlManager = new DeviceControlManager();